﻿namespace Digitalmes.Application.Mes;

/// <summary>
/// 返工上线服务
/// </summary>
public sealed class ReworkRelaunchService : IApplicationService
{
    private readonly SugarRepository<ReworkDoc> _reworkDocRepo;

    public ReworkRelaunchService(SugarRepository<ReworkDoc> reworkDocRepo)
    {
        _reworkDocRepo = reworkDocRepo;
    }

    /// <summary>
    /// 校验返工上线
    /// </summary>
    /// <param name="transSn">SN 信息</param>
    /// <param name="curProcCode">当前进站的工序编号</param>
    /// <returns>
    /// cando => 是否能在当前工序进行作业;
    /// isReworkProc => 当前工序是否是返工工序（需要作业的工序，离线返工重上线不属于）；
    /// isReworkRelaunchProc => 当前工序是否是返工重上线工序；
    /// relaunchProcCode => 该产品重新上线作业工序。
    /// </returns>
    public async Task<(bool cando, bool isReworkProc, bool isReworkRelaunchProc, string relaunchProcCode)> CheckReworkAsync(ProdTransSn transSn, string curProcCode)
    {
        // 在线返工：
        //  检测当前工位是否在返工站中，若不在，则放行；
        // 离线返工再上新：
        //  检测当前工位是否是指定重上线的工位，若不是，则放行；
        var reworkDoc = await _reworkDocRepo.GetFirstAsync(s => s.Doc == transSn.ReworkDoc);
        if (reworkDoc == null)
        {
            return (false, false, false, string.Empty);
        }

        // 离线返工
        if (reworkDoc.ReworkType is ReworkTypeEnum.Offline)
        {
            // 返工还未完成，不能上线作业
            if (reworkDoc.Status != ReworkStatusEnum.Completed)
            {
                return (false, false, false, string.Empty);
            }

            // 当前工序必须和重上线工位相同
            if (reworkDoc.RelaunchProcCode == curProcCode)
            {
                return (true, true, true, reworkDoc.RelaunchProcCode);
            }

            return (false, false, false, reworkDoc.RelaunchProcCode);
        }
        else if (reworkDoc.ReworkType is ReworkTypeEnum.Online) // 在线返工，告知当前工序是否可以返工，并给出重上线作业的初始工位
        {
            // 检测返工工序是否包含当前工序
            var cando = reworkDoc.ReworkProcCodes.Contains(curProcCode);
            var isRelaunch = reworkDoc.RelaunchProcCode == curProcCode;
            return (cando, cando, isRelaunch, reworkDoc.RelaunchProcCode);
        }

        return (false, false, false, string.Empty);
    }

    /// <summary>
    /// 在线返工处理。
    /// </summary>
    /// <param name="transSn">SN 信息</param>
    /// <returns>
    /// isReworkProc => 当前是否是返工工位（在线返工）；
    /// isReworkDone => 当前是否返工结束（在线返工，最后一工位）。
    /// </returns>
    public async Task<(bool isReworkProc, bool isReworkDone)> OnlineReworkAsync(ProdTransSn transSn, string @operator)
    {
        var reworkDoc = await _reworkDocRepo.GetFirstAsync(s => s.Doc == transSn.ReworkDoc);
        if (reworkDoc == null)
        {
            return (false, false);
        }

        // 在线返工：
        //  - 产品进站时会校验 SN 状态，看是否能进站；
        //  - 若返工 NG，关闭返工单，产品状态 NG，待重新去开返工单；
        //  - 若是最后一工序，关闭返工单，重置SN新增返工标识，工单不合格数-1。
        // 
        // 离线返工：
        //  - 进站时校验重上线工序，上线工作过站后重置产品返工状态（恢复正常）。

        var (isReworkProc, isReworkDone) = (false, false);

        // 在线返工
        if (reworkDoc.ReworkType == ReworkTypeEnum.Online)
        {
            var relaunchProcId = reworkDoc.RelaunchProcId;
            var reworkProcCodes = reworkDoc.ReworkProcCodes;

            // 返工 NG，或是最后一工序，关闭返工单
            if (transSn.Status is SnStatusEnum.NG || reworkProcCodes.Last() == transSn.CurProcCode)
            {
                reworkDoc.Operator = @operator;
                reworkDoc.Result = transSn.Status switch
                {
                    SnStatusEnum.OK => ReworkResultEnum.OK,
                    SnStatusEnum.NG => ReworkResultEnum.NG,
                    _ => ReworkResultEnum.OK,
                };
                reworkDoc.Status = ReworkStatusEnum.Completed;
                reworkDoc.CompletedTime = DateTime.Now;
                await _reworkDocRepo.UpdateAsync(reworkDoc, s => new { s.Operator, s.Result, s.Status, s.CompletedTime, s.UpdateTime });

                // 返工工位，且返工结束
                (isReworkProc, isReworkDone) = (true, true);
            }
            else
            {
                if (transSn.ReworkFlag is not ReworkFlagEnum.Working)
                {
                    reworkDoc.Operator = @operator;
                    reworkDoc.Status = ReworkStatusEnum.Reworking;
                    await _reworkDocRepo.UpdateAsync(reworkDoc, s => new { s.Operator, s.Status, s.UpdateTime });

                    // 返工工位，但未结束
                    (isReworkProc, isReworkDone) = (true, false);
                }
            }
        }
        else if (reworkDoc.ReworkType == ReworkTypeEnum.Offline)
        {
            // 重新上线，非返工工位
            (isReworkProc, isReworkDone) = (false, false);
        }

        return (isReworkProc, isReworkDone);
    }
}
